package com.ruoyi.learn.java.algorithm.sort;

/**
 * 快速排序的工作原理基于分治法，核心是分区操作：
 * 选择基准：从数组中选择一个元素作为 "基准"(pivot)
 * 分区：重新排列数组，所有比基准值小的元素放在基准前面，所有比基准值大的元素放在基准后面
 * 递归排序：递归地将小于基准值的子数组和大于基准值的子数组进行排序
 * 快速排序的复杂度分析：
 * 时间复杂度：平均情况为O(n log n)，最坏情况为O(n²)（当数组已排序且总是选择最左 / 最右元素作为基准时），但实际应用中通过合理选择基准（如随机选择或三数取中）可避免最坏情况
 * 空间复杂度：O(log n) 到 O(n)，主要是递归调用栈所占用的空间
 * 稳定性：不稳定的排序算法，相等元素的相对顺序可能改变
 * 快速排序在实践中通常比归并排序更快，因为它的内部循环可以更高效地实现，且缓存局部性更好。它是许多编程语言标准库中排序函数的首选实现。
 */
public class QuickSort {
    // 主方法：对数组进行快速排序
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            // 分区操作，返回基准元素的正确位置
            int pi = partition(arr, low, high);

            // 递归排序基准元素左边的子数组
            quickSort(arr, low, pi - 1);
            // 递归排序基准元素右边的子数组
            quickSort(arr, pi + 1, high);
        }
    }

    // 分区操作：选择一个基准元素，将小于它的放左边，大于它的放右边
    private static int partition(int[] arr, int low, int high) {
        // int low = 0, int high = 99
        // 选择最右边的元素作为基准
        int pivot = arr[high];

        // i是小于基准区域的边界索引
        int i = (low - 1);

        for (int j = low; j < high; j++) {
            // 如果当前元素小于或等于基准
            if (arr[j] <= pivot) {
                i++;

                // 交换arr[i]和arr[j]
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }

        // 将基准元素放到正确的位置（i+1）
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;

        return i + 1;
    }

    // 打印数组
    public static void printArray(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n; ++i) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    // 测试主方法
    public static void main(String args[]) {
        int[] arr = {10, 7, 8, 9, 1, 5};
        int n = arr.length;

        System.out.println("排序前的数组:");
        printArray(arr);

        quickSort(arr, 0, n - 1);

        System.out.println("排序后的数组:");
        printArray(arr);
    }
}
